﻿#include "MLFrame.h"

extern ScreenQuad screenQuad;

MLFrame::MLFrame(int frame_size_x, int frame_size_y) {
    _frame_size_x = frame_size_x;
    _frame_size_y = frame_size_y;
    glGenFramebuffers(1, &fbo);
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_size_x, frame_size_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
    Utils::clearFrame(fbo);
}

void MLFrame::clear() const {
    glDeleteFramebuffers(1, &fbo);
    glDeleteTextures(1, &texture);
    if (rbo != 0) {
        glDeleteRenderbuffers(1, &rbo);
    }
}

MLFrame MLFrame::copy() const {
    MLFrame new_frame(_frame_size_x, _frame_size_y);
    new_frame.fbo = fbo;
    new_frame.rbo = rbo;
    new_frame.texture = texture;
    return new_frame;
}

uint8_t *MLFrame::getFrame(FrameWriter writer) const {
    uint8_t *result = Utils::getFrame(writer, fbo, texture);
    return result;
}

void MLFrame::mix(const MLFrame &other_frame, const GLuint shaderProgram) {
    mix(other_frame.fbo, other_frame.texture, other_frame.rbo, shaderProgram);
}

void MLFrame::mix_alpha(const MLFrame &other_frame, double self_alpha, double other_alpha, const GLuint shaderProgram) {
    mix_alpha(other_frame.texture, self_alpha, other_alpha, shaderProgram);
}

void MLFrame::mix(GLuint otherFbo, GLuint otherTexture, GLuint otherRbo, const GLuint shaderProgram) {
    glFinish();
    // 保存当前OpenGL状态
    GLint oldFBO;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFBO);
    GLint oldViewport[4];
    glGetIntegerv(GL_VIEWPORT, oldViewport);

    // 绑定当前FBO并设置视口
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glViewport(0, 0, _frame_size_x, _frame_size_y);

    // 使用混合着色器
    glUseProgram(shaderProgram);

    // 绑定当前帧缓冲的纹理和输入的FBO纹理
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture); // 当前FBO的纹理

    // 绑定输入FBO的纹理
    glActiveTexture(GL_TEXTURE1);
    // 确保输入FBO的纹理内容已更新
    glBindTexture(GL_TEXTURE_2D, otherTexture);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 设置纹理uniform
    GLint loc1 = glGetUniformLocation(shaderProgram, "texture1");
    GLint loc2 = glGetUniformLocation(shaderProgram, "texture2");

    if (loc1 != -1)
        glUniform1i(loc1, 0);
    if (loc2 != -1)
        glUniform1i(loc2, 1);

    // 确保全屏四边形初始化
    static bool quadInitialized = []() {
        screenQuad.initialize();
        return true;
    }();

    // 渲染全屏四边形
    glBindVertexArray(screenQuad.VAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);

    // 恢复状态
    glDisable(GL_BLEND);
    glBindFramebuffer(GL_FRAMEBUFFER, oldFBO);
    glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
    glActiveTexture(GL_TEXTURE0);
}

void MLFrame::mix_alpha(GLuint otherTexture, double self_alpha, double other_alpha, const GLuint shaderProgram) {
    glFinish();
    // 保存当前OpenGL状态
    GLint oldFBO;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFBO);
    GLint oldViewport[4];
    glGetIntegerv(GL_VIEWPORT, oldViewport);

    // 绑定当前FBO并设置视口
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glViewport(0, 0, _frame_size_x, _frame_size_y);

    // 使用混合着色器
    glUseProgram(shaderProgram);

    // 绑定当前帧缓冲的纹理和输入的FBO纹理
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture); // 当前FBO的纹理

    // 绑定输入FBO的纹理
    glActiveTexture(GL_TEXTURE1);
    // 确保输入FBO的纹理内容已更新
    glBindTexture(GL_TEXTURE_2D, otherTexture);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 设置纹理uniform
    GLint loc1 = glGetUniformLocation(shaderProgram, "texture1");
    GLint loc2 = glGetUniformLocation(shaderProgram, "texture2");
    GLint self_a_loc = glGetUniformLocation(shaderProgram, "self_alpha");
    GLint other_a_loc = glGetUniformLocation(shaderProgram, "other_alpha");

    if (loc1 != -1)
        glUniform1i(loc1, 0);
    if (loc2 != -1)
        glUniform1i(loc2, 1);
    glUniform1f(self_a_loc, (float) self_alpha); // 新增
    glUniform1f(other_a_loc, (float) other_alpha); // 新增
    // std::cerr << self_alpha << " " << other_alpha << std::endl; 输出为0.8 1
    // std::cerr << self_a_loc << " " << other_a_loc << std::endl; 输出为1 0

    // 确保全屏四边形初始化
    static bool quadInitialized = []() {
        screenQuad.initialize();
        return true;
    }();

    // 渲染全屏四边形
    glBindVertexArray(screenQuad.VAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);

    // 恢复状态
    glDisable(GL_BLEND);
    glBindFramebuffer(GL_FRAMEBUFFER, oldFBO);
    glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
    glActiveTexture(GL_TEXTURE0);
}
